#pragma once
#pragma once
#include <map>
#include <queue>
#include <vector>

class CCriticalLock
{
public:
	CCriticalLock(CRITICAL_SECTION &cs) :m_cs(cs)
	{
		::EnterCriticalSection(&m_cs);
	}
	~CCriticalLock()
	{
		::LeaveCriticalSection(&m_cs);
	}
private:
	CRITICAL_SECTION &m_cs;
};

template <class T, class O = int>
struct ThreadBufferData
{
	T *pData;
	int nDataSize;

	ThreadBufferData()
	{
		::InitializeCriticalSection(&m_cs);
		pData = NULL;
		nDataSize = 0;
	}

	~ThreadBufferData()
	{
		if (pData)
			delete[]pData;
		pData = NULL;
		::DeleteCriticalSection(&m_cs);
	}

	void Clear()
	{
		if (pData)
			delete[]pData;
		pData = NULL;
		nDataSize = 0;
	}

	void SetOData(const O &data)
	{
		m_o = data;
	}
	operator CRITICAL_SECTION&()
	{
		return m_cs;
	}
private:
	CRITICAL_SECTION m_cs;
	O m_o;
private:
	ThreadBufferData(const ThreadBufferData &);
	const ThreadBufferData & operator = (const ThreadBufferData &);
};

template<class _Key,class _Val>
class CSafeMap
{
public:
	CSafeMap()
	{
		InitializeCriticalSection(&m_cs);
	}
	~CSafeMap()
	{
		DeleteCriticalSection(&m_cs);
	}

	void Clear()
	{
		CCriticalLock lock(m_cs);
		m_map.clear();
	}

	_Val SetVal(const _Key &k, _Val &v)
	{
		CCriticalLock lock(m_cs);
		m_map[k] = v;
		return v;
	}

	bool GetVal(const _Key &k, _Val &v)
	{
		CCriticalLock lock(m_cs);
		if (m_map.count(k))
		{
			v = m_map[k];
			return true;
		}
		return false;
	}

	void Swap(std::map<_Key, _Val> &vmap)
	{
		CCriticalLock lock(m_cs);
		m_map.swap(vmap);
	}

	void Copy(std::map<_Key, _Val> &vmap)
	{
		CCriticalLock lock(m_cs);
		vmap = m_map;
	}

	void Erase(const _Key &k)
	{
		CCriticalLock lock(m_cs);
		m_map.erase(k);
	}

	bool Empty()
	{
		CCriticalLock lock(m_cs);
		return m_map.empty();
	}


private:
	std::map<_Key, _Val> m_map;
	CRITICAL_SECTION m_cs;
};

template<class v>
class CThreadQueue
{
public:
	CThreadQueue()
	{
		InitializeCriticalSection(&m_cs);
	}
	~CThreadQueue()
	{
		DeleteCriticalSection(&m_cs);
	}

	void Clear()
	{
		CCriticalLock lock(m_cs);
		std::queue<v> emptyqueue;
		m_queue.swap(emptyqueue);
	}

	bool Pop(v &val)
	{
		CCriticalLock lock(m_cs);
		if (m_queue.empty()) return false;
		val = m_queue.front();
		m_queue.pop();
		return true;
	}

	void Push(const v &val)
	{
		CCriticalLock lock(m_cs);
		m_queue.push(val);
	}

	void Swap(std::queue<v> &queue)
	{
		CCriticalLock lock(m_cs);
		m_queue.swap(queue);
	}

private:
	std::queue<v> m_queue;
	CRITICAL_SECTION m_cs;
};


class CTimerPool
{
	struct TimerData
	{
		UINT uElapse;
		HWND hWnd;
		UINT nTimerID;
		UINT nLastexecTime;
		VOID(CALLBACK* TimerProc)(HWND hWnd, UINT nTimerID);
	};
public:
	static void Init(size_t nTimerHandle = 4)
	{
		if (m_bInit) return;
		m_bInit = true;
		InitializeCriticalSection(&m_cs);
		for (int i = 0; i < nTimerHandle;++i)
		{
			CloseHandle(CreateThread(NULL, 0, _timerthread, NULL, 0, NULL));
		}
	}

	static void ClearTimer()
	{
		//DeleteCriticalSection(&m_cs);
		CCriticalLock lock(m_cs);
		m_mapTimer.clear();
	}

	static void SetTimer(HWND hWnd, UINT nTimerID, UINT uElapse, VOID(CALLBACK* TimerProc)(HWND hWnd, UINT nTimerID))
	{
		TimerData tmdata;
		tmdata.uElapse = uElapse;
		tmdata.hWnd = hWnd;
		tmdata.nTimerID = nTimerID;
		tmdata.TimerProc = TimerProc;
		tmdata.nLastexecTime = 0;
		CCriticalLock lock(m_cs);
		m_mapTimer[nTimerID] = tmdata;
	}

	static void KillTimer(UINT nTimerID)
	{
		CCriticalLock lock(m_cs);
		m_mapTimer.erase(nTimerID);
	}
private:
	static DWORD WINAPI _timerthread(LPVOID lparam)
	{
		while (true)
		{
			std::map<UINT, TimerData> vMap; 
			{
				CCriticalLock lock(m_cs);
				if (m_mapTimer.empty())
				{
					Sleep(10);
					continue;
				}
				else
				{
					vMap  = m_mapTimer;
				}
			}
			
			for (std::map<UINT, TimerData>::iterator it = vMap.begin();
				it != vMap.end();++it)
			{
				UINT ntime = GetTickCount();
				bool bCall = false;
				{
					CCriticalLock lock(m_cs);
					if (m_mapTimer.count(it->first))
					{
						auto &item = m_mapTimer[it->first];

						if (item.nLastexecTime == 0 || 
							(ntime > item.nLastexecTime  && ntime - item.nLastexecTime >= item.uElapse))
						{
							item.nLastexecTime = ntime;
							bCall = true;
							it->second = item;
						}
					} 
				}

				if (bCall && it->second.TimerProc)
				{
					it->second.TimerProc(it->second.hWnd, it->second.nTimerID);
				}
			}
		}
	}

private:
	static bool m_bInit;
	static std::map<UINT, TimerData> m_mapTimer;
	static CRITICAL_SECTION m_cs;
};